
 <!DOCTYPE HTML>
<html >
<head>
  <meta charset="UTF-8">
  
    <title>谭俊熙_Fabric-sdk-java调试 | B3434lockchain</title>
    <meta name="viewport" content="width=device-width, initial-scale=1,user-scalable=no">
    
    <meta name="author" content="b3434lockchain">
    

    
    <meta name="description" content="环境准备 JDK 1.8+ Apache Maven IDEA / eclipse  下载项目1git clone https://github.com/hyperledger/fabric-sdk-java 运行Fabric环境12cd fabric-sdk-java/src/test/fixture/sdkintegration./fabric.sh up 运行结果 导入项目由于选择的是ecl">
<meta name="keywords" content="谭俊熙,报告">
<meta property="og:type" content="article">
<meta property="og:title" content="谭俊熙_Fabric-sdk-java调试">
<meta property="og:url" content="http://b3434lockchain.gitee.io/2018/11/05/tanjunxi/tanjunxi4/index.html">
<meta property="og:site_name" content="B3434lockchain">
<meta property="og:description" content="环境准备 JDK 1.8+ Apache Maven IDEA / eclipse  下载项目1git clone https://github.com/hyperledger/fabric-sdk-java 运行Fabric环境12cd fabric-sdk-java/src/test/fixture/sdkintegration./fabric.sh up 运行结果 导入项目由于选择的是ecl">
<meta property="og:locale" content="default">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/14229679-fbb78f00747ef41a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/14229679-d871a465ae155c61.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/14229679-09429223effcd889.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/14229679-cc35954addffc6af.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/14229679-27dc078aefb4df38.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:updated_time" content="2018-11-05T12:26:56.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="谭俊熙_Fabric-sdk-java调试">
<meta name="twitter:description" content="环境准备 JDK 1.8+ Apache Maven IDEA / eclipse  下载项目1git clone https://github.com/hyperledger/fabric-sdk-java 运行Fabric环境12cd fabric-sdk-java/src/test/fixture/sdkintegration./fabric.sh up 运行结果 导入项目由于选择的是ecl">
<meta name="twitter:image" content="https://upload-images.jianshu.io/upload_images/14229679-fbb78f00747ef41a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">

    
    <link rel="alternative" href="/atom.xml" title="B3434lockchain" type="application/atom+xml">
    
    
    <link rel="icon" href="/img/favicon.ico">
    
    
    <link rel="apple-touch-icon" href="/img/jacman.jpg">
    <link rel="apple-touch-icon-precomposed" href="/img/jacman.jpg">
    
    <link rel="stylesheet" href="/css/style.css">
</head>

  <body>
    <header>
      
<div>
		
			<div id="imglogo">
				<a href="/"><img src="/img/logo.png" alt="B3434lockchain" title="B3434lockchain"/></a>
			</div>
			
			<div id="textlogo">
				<h1 class="site-name"><a href="/" title="B3434lockchain">B3434lockchain</a></h1>
				<h2 class="blog-motto"></h2>
			</div>
			<div class="navbar"><a class="navbutton navmobile" href="#" title="Menu">
			</a></div>
			<nav class="animated">
				<ul>
					<ul>
					 
						<li><a href="/">Home</a></li>
					
						<li><a href="/archives">Archives</a></li>
					
						<li><a href="/about">About</a></li>
					
					<li>
 					
						<form class="search" action="https://www.baidu.com" target="_blank">
							<label>Search</label>
						<input name="s" type="hidden" value=  ><input type="text" name="q" size="30" placeholder="Search"><br>
						</form>
					
					</li>
				</ul>
			</nav>			
</div>
    </header>
    <div id="container">
      <div id="main" class="post" itemscope itemprop="blogPost">
  
	<article itemprop="articleBody"> 
		<header class="article-info clearfix">
  <h1 itemprop="name">
    
      <a href="/2018/11/05/tanjunxi/tanjunxi4/" title="谭俊熙_Fabric-sdk-java调试" itemprop="url">谭俊熙_Fabric-sdk-java调试</a>
  </h1>
  <p class="article-author">By
       
		<a href="/about" title="b3434lockchain" target="_blank" itemprop="author">b3434lockchain</a>
		
  <p class="article-time">
    <time datetime="2018-11-05T03:00:00.000Z" itemprop="datePublished"> Published 2018-11-05</time>
    
  </p>
</header>
	<div class="article-content">
		
		<div id="toc" class="toc-article">
			<strong class="toc-title">Contents</strong>
		
			<ol class="toc"><li class="toc-item toc-level-5"><a class="toc-link" href="#环境准备"><span class="toc-number">1.</span> <span class="toc-text">环境准备</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#下载项目"><span class="toc-number">2.</span> <span class="toc-text">下载项目</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#运行Fabric环境"><span class="toc-number">3.</span> <span class="toc-text">运行Fabric环境</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#导入项目"><span class="toc-number">4.</span> <span class="toc-text">导入项目</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#运行测试Demo——End2endIT-java"><span class="toc-number">5.</span> <span class="toc-text">运行测试Demo——End2endIT.java</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#End2endIT源码分析-注释都在代码中"><span class="toc-number">6.</span> <span class="toc-text">End2endIT源码分析(注释都在代码中)</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#总结"><span class="toc-number">7.</span> <span class="toc-text">总结</span></a></li></ol>
		
		</div>
		
		<h5 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h5><ol>
<li>JDK 1.8+</li>
<li>Apache Maven</li>
<li>IDEA / eclipse</li>
</ol>
<h5 id="下载项目"><a href="#下载项目" class="headerlink" title="下载项目"></a>下载项目</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git clone https://github.com/hyperledger/fabric-sdk-java</span><br></pre></td></tr></table></figure>
<h5 id="运行Fabric环境"><a href="#运行Fabric环境" class="headerlink" title="运行Fabric环境"></a>运行Fabric环境</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cd fabric-sdk-java/src/test/fixture/sdkintegration</span><br><span class="line">./fabric.sh up</span><br></pre></td></tr></table></figure>
<p>运行结果<br><img src="https://upload-images.jianshu.io/upload_images/14229679-fbb78f00747ef41a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="fabric-up.png"></p>
<h5 id="导入项目"><a href="#导入项目" class="headerlink" title="导入项目"></a>导入项目</h5><p>由于选择的是eclipse，所以一直无法配置好依赖，使得一直没有能够成功导入项目，最后放弃选择使用IDEA，IDEA导入maven项目后，只需安装protobuf support，再进行complie即可，这里就不详述了。</p>
<h5 id="运行测试Demo——End2endIT-java"><a href="#运行测试Demo——End2endIT-java" class="headerlink" title="运行测试Demo——End2endIT.java"></a>运行测试Demo——End2endIT.java</h5><p>运行结果分析</p>
<ol>
<li>先构建通道foo，把org1加入该通道，运行该通道</li>
</ol>
<hr>
<p><img src="https://upload-images.jianshu.io/upload_images/14229679-d871a465ae155c61.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="run-channel.png"></p>
<ol start="2">
<li>初始化a为100，b为200，并把此交易送至orderer中</li>
</ol>
<hr>
<p><img src="https://upload-images.jianshu.io/upload_images/14229679-09429223effcd889.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="set-a-b.png"></p>
<ol start="3">
<li>a转账100给b，背书后，把交易送至orderer</li>
</ol>
<hr>
<p><img src="https://upload-images.jianshu.io/upload_images/14229679-cc35954addffc6af.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="a-100to-b.png"></p>
<ol start="4">
<li>查询b的值</li>
</ol>
<hr>
<p><img src="https://upload-images.jianshu.io/upload_images/14229679-27dc078aefb4df38.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="query-b.png"></p>
<ol start="5">
<li>后面就是创建调用另一个通道bar，进行相同的操作，这里也不详细罗列了</li>
</ol>
<h5 id="End2endIT源码分析-注释都在代码中"><a href="#End2endIT源码分析-注释都在代码中" class="headerlink" title="End2endIT源码分析(注释都在代码中)"></a>End2endIT源码分析(注释都在代码中)</h5><ol>
<li><p>先执行checkConfig()方法检查配置项</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">@Before</span><br><span class="line">public void checkConfig() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, MalformedURLException, org.hyperledger.fabric_ca.sdk.exception.InvalidArgumentException &#123;</span><br><span class="line">    out(&quot;\n\n\nRUNNING: %s.\n&quot;, testName);</span><br><span class="line">    resetConfig();//先重置配置文件org.hyperledger.fabric.sdk.helper.Config，config主要是fabric需要的配置项</span><br><span class="line">    configHelper.customizeConfig();//调用命令行输入的指定变量，覆盖掉上面的Config配置</span><br><span class="line"></span><br><span class="line">    testSampleOrgs = testConfig.getIntegrationTestsSampleOrgs();//获取testConfig配置的组织，TestConfig在End2endIT已经被new出来，里面也有大量的测试配置项</span><br><span class="line">    for (SampleOrg sampleOrg : testSampleOrgs) &#123;//设置颁发证书的CA证书机构</span><br><span class="line">        String caName = sampleOrg.getCAName(); </span><br><span class="line">        if (caName != null &amp;&amp; !caName.isEmpty()) &#123;</span><br><span class="line">            sampleOrg.setCAClient(HFCAClient.createNewInstance(caName, sampleOrg.getCALocation(), sampleOrg.getCAProperties()));</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            sampleOrg.setCAClient(HFCAClient.createNewInstance(sampleOrg.getCALocation(), sampleOrg.getCAProperties()));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>执行setup()方法</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">@Test</span><br><span class="line">public void setup() throws Exception &#123;</span><br><span class="line">    if (sampleStoreFile.exists()) &#123;</span><br><span class="line">        sampleStoreFile.delete();//模拟数据库存储使用了HFCSampletest.properties</span><br><span class="line">    &#125;</span><br><span class="line">    sampleStore = new SampleStore(sampleStoreFile);//初始化存储</span><br><span class="line">    enrollUsersSetup(sampleStore);// 利用ca做初始化</span><br><span class="line">    runFabricTest(sampleStore);//核心方法</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>分析enrollUsersSetup()方法</p>
</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line">for (SampleOrg sampleOrg : testSampleOrgs) &#123;</span><br><span class="line"></span><br><span class="line">        HFCAClient ca = sampleOrg.getCAClient();//获得ca客户端</span><br><span class="line"></span><br><span class="line">        final String orgName = sampleOrg.getName();//组织名称</span><br><span class="line">        final String mspid = sampleOrg.getMSPID();//组织证书ID</span><br><span class="line">        ca.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());//设置CA客户端证书套件</span><br><span class="line"></span><br><span class="line">        if (testConfig.isRunningFabricTLS()) &#123;</span><br><span class="line">            //从CA客户端获取TLS证书</span><br><span class="line">            final EnrollmentRequest enrollmentRequestTLS = new EnrollmentRequest();</span><br><span class="line">            enrollmentRequestTLS.addHost(&quot;localhost&quot;);</span><br><span class="line">            enrollmentRequestTLS.setProfile(&quot;tls&quot;);</span><br><span class="line">            final Enrollment enroll = ca.enroll(&quot;admin&quot;, &quot;adminpw&quot;, enrollmentRequestTLS);</span><br><span class="line">            final String tlsCertPEM = enroll.getCert();</span><br><span class="line">            final String tlsKeyPEM = getPEMStringFromPrivateKey(enroll.getKey());</span><br><span class="line"></span><br><span class="line">            final Properties tlsProperties = new Properties();</span><br><span class="line"></span><br><span class="line">            tlsProperties.put(&quot;clientKeyBytes&quot;, tlsKeyPEM.getBytes(UTF_8));</span><br><span class="line">            tlsProperties.put(&quot;clientCertBytes&quot;, tlsCertPEM.getBytes(UTF_8));</span><br><span class="line">            clientTLSProperties.put(sampleOrg.getName(), tlsProperties);</span><br><span class="line"></span><br><span class="line">            sampleStore.storeClientPEMTLCertificate(sampleOrg, tlsCertPEM);</span><br><span class="line">            sampleStore.storeClientPEMTLSKey(sampleOrg, tlsKeyPEM);</span><br><span class="line">        &#125;</span><br><span class="line">        //检查是否连接成功</span><br><span class="line">        HFCAInfo info = ca.info();</span><br><span class="line">        assertNotNull(info);</span><br><span class="line">        String infoName = info.getCAName();</span><br><span class="line">        if (infoName != null &amp;&amp; !infoName.isEmpty()) &#123;</span><br><span class="line">            assertEquals(ca.getCAName(), infoName);</span><br><span class="line">        &#125;</span><br><span class="line">        //获取组织管理员（admin）</span><br><span class="line">        SampleUser admin = sampleStore.getMember(TEST_ADMIN_NAME, orgName);</span><br><span class="line">        if (!admin.isEnrolled()) &#123; </span><br><span class="line">            //管理员只需在CA客户端进行登记</span><br><span class="line">            admin.setEnrollment(ca.enroll(admin.getName(), &quot;adminpw&quot;));</span><br><span class="line">            admin.setMspId(mspid);</span><br><span class="line">        &#125;</span><br><span class="line">        //获取普通用户</span><br><span class="line">        SampleUser user = sampleStore.getMember(testUser1, sampleOrg.getName());</span><br><span class="line">        if (!user.isRegistered()) &#123; </span><br><span class="line">            //如果未注册则生成注册请求</span><br><span class="line">            RegistrationRequest rr = new RegistrationRequest(user.getName(), &quot;org1.department1&quot;);</span><br><span class="line">            //设置密码（注册请求发出去后，CA会返回一个密码）</span><br><span class="line">            user.setEnrollmentSecret(ca.register(rr, admin));</span><br><span class="line">        &#125;</span><br><span class="line">        if (!user.isEnrolled()) &#123;</span><br><span class="line">            //如果未登记则登记</span><br><span class="line">            user.setEnrollment(ca.enroll(user.getName(), user.getEnrollmentSecret()));</span><br><span class="line">            user.setMspId(mspid);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        final String sampleOrgName = sampleOrg.getName();</span><br><span class="line">        final String sampleOrgDomainName = sampleOrg.getDomainName();//获取组织的命名域</span><br><span class="line">        //使用证书文件生成用户信息</span><br><span class="line">        SampleUser peerOrgAdmin = sampleStore.getMember(sampleOrgName + &quot;Admin&quot;, sampleOrgName, sampleOrg.getMSPID(),</span><br><span class="line">                Util.findFileSk(Paths.get(testConfig.getTestChannelPath(), &quot;crypto-config/peerOrganizations/&quot;,</span><br><span class="line">                        sampleOrgDomainName, format(&quot;/users/Admin@%s/msp/keystore&quot;, sampleOrgDomainName)).toFile()),</span><br><span class="line">                Paths.get(testConfig.getTestChannelPath(), &quot;crypto-config/peerOrganizations/&quot;, sampleOrgDomainName,</span><br><span class="line">                        format(&quot;/users/Admin@%s/msp/signcerts/Admin@%s-cert.pem&quot;, sampleOrgDomainName, sampleOrgDomainName)).toFile());</span><br><span class="line">      </span><br><span class="line">        sampleOrg.setPeerAdmin(peerOrgAdmin);//设置节点管理员（一个特殊的用户，可以创建通道，加入节点以及安装链码）</span><br><span class="line"></span><br><span class="line">        sampleOrg.addUser(user);//组织内添加用户</span><br><span class="line">        sampleOrg.setAdmin(admin); //设置管理员身份</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<ol start="4">
<li>分析 runFabricTest()方法</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line">////////////////////////////</span><br><span class="line">// Setup client</span><br><span class="line"></span><br><span class="line">//Create instance of client.</span><br><span class="line">HFClient client = HFClient.createNewInstance();//初始化一个客户端，类似cli</span><br><span class="line"></span><br><span class="line">client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());//设置加密算法</span><br><span class="line"></span><br><span class="line">////////////////////////////</span><br><span class="line">//Construct and run the channels</span><br><span class="line">// 获取peerOrg1组织1</span><br><span class="line">SampleOrg sampleOrg = testConfig.getIntegrationTestsSampleOrg(&quot;peerOrg1&quot;);</span><br><span class="line">// 构建一个channel通道，Org1加入到该通道中</span><br><span class="line">Channel fooChannel = constructChannel(FOO_CHANNEL_NAME, client, sampleOrg);</span><br><span class="line">// 保存通道名称到数据库中(这里是存储到上面方法文件)</span><br><span class="line">sampleStore.saveChannel(fooChannel);</span><br><span class="line">// 安装链码、实例化链码、执行一个查询测试</span><br><span class="line">runChannel(client, fooChannel, true, sampleOrg, 0);</span><br><span class="line"></span><br><span class="line">assertFalse(fooChannel.isShutdown());</span><br><span class="line">fooChannel.shutdown(true); // Force foo channel to shutdown clean up resources.</span><br><span class="line">assertTrue(fooChannel.isShutdown());</span><br><span class="line"></span><br><span class="line">assertNull(client.getChannel(FOO_CHANNEL_NAME));</span><br><span class="line">out(&quot;\n&quot;);</span><br><span class="line">// 下面是组织2的过程，跟组织1是类似的</span><br><span class="line">sampleOrg = testConfig.getIntegrationTestsSampleOrg(&quot;peerOrg2&quot;);</span><br><span class="line">Channel barChannel = constructChannel(BAR_CHANNEL_NAME, client, sampleOrg);</span><br><span class="line">assertTrue(barChannel.isInitialized());</span><br><span class="line">/**</span><br><span class="line"> * sampleStore.saveChannel uses &#123;@link Channel#serializeChannel()&#125;</span><br><span class="line"> */</span><br><span class="line">sampleStore.saveChannel(barChannel);</span><br><span class="line">assertFalse(barChannel.isShutdown());</span><br><span class="line">runChannel(client, barChannel, true, sampleOrg, 100); //run a newly constructed bar channel with different b value!</span><br><span class="line">//let bar channel just shutdown so we have both scenarios.</span><br><span class="line"></span><br><span class="line">out(&quot;\nTraverse the blocks for chain %s &quot;, barChannel.getName());</span><br><span class="line">// 对区块进行各种查询，包括区块读写集、区块数量高度等</span><br><span class="line">blockWalker(client, barChannel);</span><br><span class="line"></span><br><span class="line">assertFalse(barChannel.isShutdown());</span><br><span class="line">assertTrue(barChannel.isInitialized());</span><br><span class="line">out(&quot;That&apos;s all folks!&quot;);</span><br></pre></td></tr></table></figure>
<ol start="5">
<li>分析constructChannel()方法(<strong>重点1</strong>)</li>
</ol>
<p>a. 获取peer的admin用户，实际上是crytogen根据crypto-config.yaml配置的默认admin账户</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">SampleUser peerAdmin = sampleOrg.getPeerAdmin();</span><br><span class="line">client.setUserContext(peerAdmin);</span><br></pre></td></tr></table></figure>
<p>b. 接着是初始化orderer排序节点对象</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">Collection&lt;Orderer&gt; orderers = new LinkedList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">for (String orderName : sampleOrg.getOrdererNames()) &#123;</span><br><span class="line"></span><br><span class="line">    Properties ordererProperties = testConfig.getOrdererProperties(orderName);</span><br><span class="line"></span><br><span class="line">    //example of setting keepAlive to avoid timeouts on inactive http2 connections.</span><br><span class="line">    // Under 5 minutes would require changes to server side to accept faster ping rates.</span><br><span class="line">    ordererProperties.put(&quot;grpc.NettyChannelBuilderOption.keepAliveTime&quot;, new Object[] &#123;5L, TimeUnit.MINUTES&#125;);</span><br><span class="line">    ordererProperties.put(&quot;grpc.NettyChannelBuilderOption.keepAliveTimeout&quot;, new Object[] &#123;8L, TimeUnit.SECONDS&#125;);</span><br><span class="line">    ordererProperties.put(&quot;grpc.NettyChannelBuilderOption.keepAliveWithoutCalls&quot;, new Object[] &#123;true&#125;);</span><br><span class="line"></span><br><span class="line">    orderers.add(client.newOrderer(orderName, sampleOrg.getOrdererLocation(orderName),</span><br><span class="line">            ordererProperties));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>c. 创建一个channel，这里使用的是Configtxgen 生成的“通道配置”文件</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">//Just pick the first orderer in the list to create the channel. </span><br><span class="line">  Orderer anOrderer = orderers.iterator().next();//选择第一个排序节点进行创建通道 </span><br><span class="line">  orderers.remove(anOrderer); //从排序节点集合中移除已经在使用的节点</span><br><span class="line"></span><br><span class="line">//通过读取channel.tx文件，生成信道配置对象 </span><br><span class="line">  ChannelConfiguration channelConfiguration = new ChannelConfiguration(new File(TEST_FIXTURES_PATH + &quot;/sdkintegration/e2e-2Orgs/channel/&quot; + name + &quot;.tx&quot;)); </span><br><span class="line"></span><br><span class="line">//创建信道对象，只有一个签名，就是组织节点管理员。如果创建信道策略需要更多的签名，那么他们必须添加</span><br><span class="line">  Channel newChannel = client.newChannel(name, anOrderer, channelConfiguration, client.getChannelConfigurationSignature(channelConfiguration, sampleOrg.getPeerAdmin()));</span><br><span class="line">  out(&quot;Created channel %s&quot;, name);</span><br></pre></td></tr></table></figure>
<p>d. client.newPeer创建peer节点，然后joinPeer加入通道channel中</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">boolean everyother = true; //test with both cases when doing peer eventing.</span><br><span class="line">    for (String peerName : sampleOrg.getPeerNames()) &#123;</span><br><span class="line">        String peerLocation = sampleOrg.getPeerLocation(peerName);//获取节点位置</span><br><span class="line"></span><br><span class="line">        Properties peerProperties = testConfig.getPeerProperties(peerName); //获取节点属性</span><br><span class="line">        if (peerProperties == null) &#123;</span><br><span class="line">            peerProperties = new Properties();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        //Example of setting specific options on grpc&apos;s NettyChannelBuilder</span><br><span class="line">        peerProperties.put(&quot;grpc.NettyChannelBuilderOption.maxInboundMessageSize&quot;, 9000000);</span><br><span class="line"></span><br><span class="line">        Peer peer = client.newPeer(peerName, peerLocation, peerProperties);//通过客户端生成节点对象</span><br><span class="line">        if (testConfig.isFabricVersionAtOrAfter(&quot;1.3&quot;)) &#123;</span><br><span class="line">            //加入生成的节点</span><br><span class="line">            newChannel.joinPeer(peer, createPeerOptions().setPeerRoles(EnumSet.of(PeerRole.ENDORSING_PEER, PeerRole.LEDGER_QUERY, PeerRole.CHAINCODE_QUERY, PeerRole.EVENT_SOURCE))); //Default is all roles.</span><br><span class="line"></span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            if (doPeerEventing &amp;&amp; everyother) &#123;</span><br><span class="line">                newChannel.joinPeer(peer, createPeerOptions().setPeerRoles(EnumSet.of(PeerRole.ENDORSING_PEER, PeerRole.LEDGER_QUERY, PeerRole.CHAINCODE_QUERY, PeerRole.EVENT_SOURCE))); //Default is all roles.</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">                // Set peer to not be all roles but eventing.</span><br><span class="line">                newChannel.joinPeer(peer, createPeerOptions().setPeerRoles(EnumSet.of(PeerRole.ENDORSING_PEER, PeerRole.LEDGER_QUERY, PeerRole.CHAINCODE_QUERY)));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        out(&quot;Peer %s joined channel %s&quot;, peerName, name);</span><br><span class="line">        everyother = !everyother;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>e. 给channel设置监听事件的grpc接口，最后进行初始化</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">//获取组织内事件记录节点集合</span><br><span class="line">for (String eventHubName : sampleOrg.getEventHubNames()) &#123;</span><br><span class="line">        //获取事件记录属性</span><br><span class="line">        final Properties eventHubProperties = testConfig.getEventHubProperties(eventHubName);</span><br><span class="line"></span><br><span class="line">        eventHubProperties.put(&quot;grpc.NettyChannelBuilderOption.keepAliveTime&quot;, new Object[] &#123;5L, TimeUnit.MINUTES&#125;);</span><br><span class="line">        eventHubProperties.put(&quot;grpc.NettyChannelBuilderOption.keepAliveTimeout&quot;, new Object[] &#123;8L, TimeUnit.SECONDS&#125;);</span><br><span class="line"></span><br><span class="line">        EventHub eventHub = client.newEventHub(eventHubName, sampleOrg.getEventHubLocation(eventHubName),</span><br><span class="line">                eventHubProperties);</span><br><span class="line">        newChannel.addEventHub(eventHub);</span><br><span class="line">    &#125;</span><br><span class="line">    //信道实例化</span><br><span class="line">    newChannel.initialize();</span><br><span class="line"></span><br><span class="line">    out(&quot;Finished initialization channel %s&quot;, name);</span><br></pre></td></tr></table></figure>
<ol start="6">
<li>分析runChannel()方法（<strong>重点2</strong>）</li>
</ol>
<p>a. 安装链码</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">if (installChaincode) &#123;</span><br><span class="line"></span><br><span class="line">       //一大段设置安装的链码信息</span><br><span class="line">       // .......</span><br><span class="line">       //发送安装链码的交易提案</span><br><span class="line">        responses = client.sendInstallProposal(installProposalRequest, peers);</span><br><span class="line"></span><br><span class="line">       //检查返回的结果，并输出相应的信息</span><br><span class="line">       //.......</span><br></pre></td></tr></table></figure>
<p>b. 实例化链码，设置背书策略</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">//实例化链码</span><br><span class="line">InstantiateProposalRequest instantiateProposalRequest = client.newInstantiationProposalRequest();</span><br><span class="line">instantiateProposalRequest.setProposalWaitTime(DEPLOYWAITTIME);</span><br><span class="line">instantiateProposalRequest.setChaincodeID(chaincodeID);</span><br><span class="line">instantiateProposalRequest.setChaincodeLanguage(CHAIN_CODE_LANG);</span><br><span class="line">instantiateProposalRequest.setFcn(&quot;init&quot;);</span><br><span class="line">instantiateProposalRequest.setArgs(new String[] &#123;&quot;a&quot;, &quot;500&quot;, &quot;b&quot;, &quot;&quot; + (200 + delta)&#125;);</span><br><span class="line">Map&lt;String, byte[]&gt; tm = new HashMap&lt;&gt;();</span><br><span class="line">tm.put(&quot;HyperLedgerFabric&quot;, &quot;InstantiateProposalRequest:JavaSDK&quot;.getBytes(UTF_8));</span><br><span class="line">tm.put(&quot;method&quot;, &quot;InstantiateProposalRequest&quot;.getBytes(UTF_8));</span><br><span class="line">instantiateProposalRequest.setTransientMap(tm);</span><br><span class="line"></span><br><span class="line">/*</span><br><span class="line">  policy OR(Org1MSP.member, Org2MSP.member) meaning 1 signature from someone in either Org1 or Org2</span><br><span class="line">  See README.md Chaincode endorsement policies section for more details.</span><br><span class="line">*/</span><br><span class="line">//设置背书策略</span><br><span class="line">ChaincodeEndorsementPolicy chaincodeEndorsementPolicy = new ChaincodeEndorsementPolicy();</span><br><span class="line">chaincodeEndorsementPolicy.fromYamlFile(new File(TEST_FIXTURES_PATH + &quot;/sdkintegration/chaincodeendorsementpolicy.yaml&quot;));</span><br><span class="line">instantiateProposalRequest.setChaincodeEndorsementPolicy(chaincodeEndorsementPolicy);</span><br><span class="line"></span><br><span class="line">out(&quot;Sending instantiateProposalRequest to all peers with arguments: a and b set to 100 and %s respectively&quot;, &quot;&quot; + (200 + delta));</span><br><span class="line">successful.clear();</span><br><span class="line">failed.clear();</span><br><span class="line"></span><br><span class="line">//检查结果，并输出相应信息</span><br></pre></td></tr></table></figure>
<p>c. 转账，查询，异常处理</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">channel.sendTransaction(successful, createTransactionOptions()</span><br><span class="line">                    .userContext(client.getUserContext())</span><br><span class="line">                    .shuffleOrders(false)</span><br><span class="line">                    .orderers(channel.getOrderers())</span><br><span class="line">                    .nOfEvents(nOfEvents)</span><br><span class="line">            ).thenApply(transactionEvent -&gt; &#123;</span><br><span class="line">            //.......</span><br><span class="line">            // 调用example_cc.go里面的move方法，a给b转账</span><br><span class="line"></span><br><span class="line">&#125;.thenApply(transactionEvent -&gt; &#123;</span><br><span class="line">                    //........</span><br><span class="line">                    // query查询b的余额</span><br><span class="line"></span><br><span class="line">                try &#123;</span><br><span class="line">&#125;).exceptionally(e -&gt; &#123;</span><br><span class="line">                    //........</span><br><span class="line">                    // 异常处理</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>d. 查询区块高度，信息之类的</p>
<h5 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h5><p>因时间有限，还并没有开始搭建自己的调用逻辑，之后会开始尝试。</p>
  
	</div>
		<footer class="article-footer clearfix">
<div class="article-catetags">


  <div class="article-tags">
  
  <span></span> <a href="/tags/谭俊熙/">谭俊熙</a><a href="/tags/报告/">报告</a>
  </div>

</div>



	<div class="article-share" id="share">
	
	  <div data-url="http://b3434lockchain.gitee.io/2018/11/05/tanjunxi/tanjunxi4/" data-title="谭俊熙_Fabric-sdk-java调试 | B3434lockchain" data-tsina="" class="share clearfix">
	  </div>
	
	</div>


</footer>

   	       
	</article>
	
<nav class="article-nav clearfix">
 
 <div class="prev" >
 <a href="/2018/11/05/lujiahao/lujiahao4/" title="周报">
  <strong>上一篇：</strong><br/>
  <span>
  周报</span>
</a>
</div>


<div class="next">
<a href="/2018/10/28/fenghuawen/fenghuawen4/"  title="冯华文第四周周报">
 <strong>下一篇：</strong><br/> 
 <span>冯华文第四周周报
</span>
</a>
</div>

</nav>

	



</div>  
      <div class="openaside"><a class="navbutton" href="#" title="Show Sidebar"></a></div>

  <div id="toc" class="toc-aside">
  <strong class="toc-title">Contents</strong>
 
 <ol class="toc"><li class="toc-item toc-level-5"><a class="toc-link" href="#环境准备"><span class="toc-number">1.</span> <span class="toc-text">环境准备</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#下载项目"><span class="toc-number">2.</span> <span class="toc-text">下载项目</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#运行Fabric环境"><span class="toc-number">3.</span> <span class="toc-text">运行Fabric环境</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#导入项目"><span class="toc-number">4.</span> <span class="toc-text">导入项目</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#运行测试Demo——End2endIT-java"><span class="toc-number">5.</span> <span class="toc-text">运行测试Demo——End2endIT.java</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#End2endIT源码分析-注释都在代码中"><span class="toc-number">6.</span> <span class="toc-text">End2endIT源码分析(注释都在代码中)</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#总结"><span class="toc-number">7.</span> <span class="toc-text">总结</span></a></li></ol>
 
  </div>

<div id="asidepart">
<div class="closeaside"><a class="closebutton" href="#" title="Hide Sidebar"></a></div>
<aside class="clearfix">

  

  
<div class="tagslist">
	<p class="asidetitle">Tags</p>
		<ul class="clearfix">
		
			
				<li><a href="/tags/周报/" title="周报">周报<sup>23</sup></a></li>
			
		
			
				<li><a href="/tags/谭俊熙/" title="谭俊熙">谭俊熙<sup>11</sup></a></li>
			
		
			
				<li><a href="/tags/苏思捷/" title="苏思捷">苏思捷<sup>5</sup></a></li>
			
		
			
				<li><a href="/tags/学习报告/" title="学习报告">学习报告<sup>5</sup></a></li>
			
		
			
				<li><a href="/tags/卢家豪/" title="卢家豪">卢家豪<sup>5</sup></a></li>
			
		
			
				<li><a href="/tags/报告/" title="报告">报告<sup>5</sup></a></li>
			
		
			
				<li><a href="/tags/苏佳鑫/" title="苏佳鑫">苏佳鑫<sup>4</sup></a></li>
			
		
			
				<li><a href="/tags/冯华文/" title="冯华文">冯华文<sup>4</sup></a></li>
			
		
			
				<li><a href="/tags/周报反馈/" title="周报反馈">周报反馈<sup>2</sup></a></li>
			
		
			
				<li><a href="/tags/吴朝捷/" title="吴朝捷">吴朝捷<sup>2</sup></a></li>
			
		
			
				<li><a href="/tags/黎宁/" title="黎宁">黎宁<sup>1</sup></a></li>
			
		
			
				<li><a href="/tags/笔记/" title="笔记">笔记<sup>1</sup></a></li>
			
		
		</ul>
</div>


</aside>
</div>
    </div>
    <footer><div id="footer" >
	
	
	<div class="social-font" class="clearfix">
		
		
		
		
		
		
		
		
		
		
	</div>
			
		

		<p class="copyright">
		
		</p>
</div>
</footer>
    <script src="/js/jquery-2.0.3.min.js"></script>
<script src="/js/jquery.imagesloaded.min.js"></script>
<script src="/js/gallery.js"></script>
<script src="/js/jquery.qrcode-0.12.0.min.js"></script>

<script type="text/javascript">
$(document).ready(function(){ 
  $('.navbar').click(function(){
    $('header nav').toggleClass('shownav');
  });
  var myWidth = 0;
  function getSize(){
    if( typeof( window.innerWidth ) == 'number' ) {
      myWidth = window.innerWidth;
    } else if( document.documentElement && document.documentElement.clientWidth) {
      myWidth = document.documentElement.clientWidth;
    };
  };
  var m = $('#main'),
      a = $('#asidepart'),
      c = $('.closeaside'),
      o = $('.openaside');
  c.click(function(){
    a.addClass('fadeOut').css('display', 'none');
    o.css('display', 'block').addClass('fadeIn');
    m.addClass('moveMain');
  });
  o.click(function(){
    o.css('display', 'none').removeClass('beforeFadeIn');
    a.css('display', 'block').removeClass('fadeOut').addClass('fadeIn');      
    m.removeClass('moveMain');
  });
  $(window).scroll(function(){
    o.css("top",Math.max(80,260-$(this).scrollTop()));
  });
  
  $(window).resize(function(){
    getSize(); 
    if (myWidth >= 1024) {
      $('header nav').removeClass('shownav');
    }else{
      m.removeClass('moveMain');
      a.css('display', 'block').removeClass('fadeOut');
      o.css('display', 'none');
      
      $('#toc.toc-aside').css('display', 'none');
        
    }
  });
});
</script>

<script type="text/javascript">
$(document).ready(function(){ 
  var ai = $('.article-content>iframe'),
      ae = $('.article-content>embed'),
      t  = $('#toc'),
      ta = $('#toc.toc-aside'),
      o  = $('.openaside'),
      c  = $('.closeaside');
  if(ai.length>0){
    ai.wrap('<div class="video-container" />');
  };
  if(ae.length>0){
   ae.wrap('<div class="video-container" />');
  };
  c.click(function(){
    ta.css('display', 'block').addClass('fadeIn');
  });
  o.click(function(){
    ta.css('display', 'none');
  });
  $(window).scroll(function(){
    ta.css("top",Math.max(140,320-$(this).scrollTop()));
  });
});
</script>


<script type="text/javascript">
$(document).ready(function(){ 
  var $this = $('.share'),
      url = $this.attr('data-url'),
      encodedUrl = encodeURIComponent(url),
      title = $this.attr('data-title'),
      tsina = $this.attr('data-tsina'),
      description = $this.attr('description');
  var html = [
  '<div class="hoverqrcode clearfix"></div>',
  '<a class="overlay" id="qrcode"></a>',
  '<a href="https://www.facebook.com/sharer.php?u=' + encodedUrl + '" class="article-share-facebook" target="_blank" title="Facebook"></a>',
  '<a href="https://twitter.com/intent/tweet?url=' + encodedUrl + '" class="article-share-twitter" target="_blank" title="Twitter"></a>',
  '<a href="#qrcode" class="article-share-qrcode" title="微信"></a>',
  '<a href="http://widget.renren.com/dialog/share?resourceUrl=' + encodedUrl + '&srcUrl=' + encodedUrl + '&title=' + title +'" class="article-share-renren" target="_blank" title="人人"></a>',
  '<a href="http://service.weibo.com/share/share.php?title='+title+'&url='+encodedUrl +'&ralateUid='+ tsina +'&searchPic=true&style=number' +'" class="article-share-weibo" target="_blank" title="微博"></a>',
  '<span title="Share to"></span>'
  ].join('');
  $this.append(html);

  $('.hoverqrcode').hide();

  var myWidth = 0;
  function updatehoverqrcode(){
    if( typeof( window.innerWidth ) == 'number' ) {
      myWidth = window.innerWidth;
    } else if( document.documentElement && document.documentElement.clientWidth) {
      myWidth = document.documentElement.clientWidth;
    };
    var qrsize = myWidth > 1024 ? 200:100;
    var options = {render: 'image', size: qrsize, fill: '#2ca6cb', text: url, radius: 0.5, quiet: 1};
    var p = $('.article-share-qrcode').position();
    $('.hoverqrcode').empty().css('width', qrsize).css('height', qrsize)
                          .css('left', p.left-qrsize/2+20).css('top', p.top-qrsize-10)
                          .qrcode(options);
  };
  $(window).resize(function(){
    $('.hoverqrcode').hide();
  });
  $('.article-share-qrcode').click(function(){
    updatehoverqrcode();
    $('.hoverqrcode').toggle();
  });
  $('.article-share-qrcode').hover(function(){}, function(){
      $('.hoverqrcode').hide();
  });
});   
</script>











<link rel="stylesheet" href="/fancybox/jquery.fancybox.css" media="screen" type="text/css">
<script src="/fancybox/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
$(document).ready(function(){ 
  $('.article-content').each(function(i){
    $(this).find('img').each(function(){
      if ($(this).parent().hasClass('fancybox')) return;
      var alt = this.alt;
      if (alt) $(this).after('<span class="caption">' + alt + '</span>');
      $(this).wrap('<a href="' + this.src + '" title="' + alt + '" class="fancybox"></a>');
    });
    $(this).find('.fancybox').each(function(){
      $(this).attr('rel', 'article' + i);
    });
  });
  if($.fancybox){
    $('.fancybox').fancybox();
  }
}); 
</script>



<!-- Analytics Begin -->





<!-- Analytics End -->

<!-- Totop Begin -->

	<div id="totop">
	<a title="Back to Top"><img src="/img/scrollup.png"/></a>
	</div>
	<script src="/js/totop.js"></script>

<!-- Totop End -->

<!-- MathJax Begin -->
<!-- mathjax config similar to math.stackexchange -->


<!-- MathJax End -->

<!-- Tiny_search Begin -->

<!-- Tiny_search End -->

  </body>
</html>
